const express = require("express");
const path = require("path");
const multiparty = require("multiparty");
const fse = require("fs-extra");
const cors = require("cors");
const bodyParser = require("body-parser");

const app = express();

app.use(bodyParser.json());
app.use(cors());

const UPLOAD_DIR = path.resolve(__dirname, "uploads");
// 提取文件后缀名
const extractExt = (filename) => {
  return filename.slice(filename.lastIndexOf("."), filename.length);
};
// 上传接口
app.post("/upload", (req, res) => {
  const form = new multiparty.Form();
  form.parse(req, async (error, fields, files) => {
    if (error) {
      res.status(401).json({
        ok: false,
        msg: "上传失败",
      });
      return;
    }
    //文件hash
    const fileHash = fields["fileHash"][0];
    // 分片hash
    const chunkHash = fields["chunkHash"][0];

    // 临时存放的目录
    const chunkPath = path.resolve(UPLOAD_DIR, fileHash);

    //如果没有该文件夹创建
    if (!fse.existsSync(chunkPath)) {
      await fse.mkdir(chunkPath);
    }
    //获取分片存放路径
    const oldPath = files["chunk"][0]["path"];

    // 将切片放到这个文件夹里
    await fse.move(oldPath, path.resolve(chunkPath, chunkHash));
    res.status(200).json({
      ok: true,
      msg: "上传成功",
    });
  });
});
// 合并接口
app.post("/merge", async (req, res) => {
  const { fileHash, fileName, size } = req.body;

  // 完整的文件路径
  let filePath = path.resolve(UPLOAD_DIR, fileHash + extractExt(fileName));
  //如果已经存在就不需要合并了
  if (fse.existsSync(filePath)) {
    res.status(200).json({
      ok: true,
      msg: "合并成功",
    });
    return;
  }
  // 获取切片文件夹
  const chunkDir = path.resolve(UPLOAD_DIR, fileHash);
  // 切片目录不存在，则无法合并切片，报异常
  if (!fse.existsSync(chunkDir)) {
    res.status(200).json({
      ok: false,
      msg: "合并失败，请重新上传",
    });
    return;
  }
  // 合并操作
  //读取切片目录下的所有文件
  const chunkPaths = await fse.readdir(chunkDir);

  // 文件排序 方便后期按顺序合并
  chunkPaths.sort((a, b) => {
    return a.split("-")[1] - b.split("-")[1];
  });
  //处理合并
  const list = chunkPaths.map((chunkName, index) => {
    return new Promise((resolve, reject) => {
      // 获取分片文件
      const chunkPath = path.resolve(chunkDir, chunkName);
      // 创建可读流
      const readStream = fse.createReadStream(chunkPath);
      // 创建可写流
      const writeStream = fse.createWriteStream(filePath, {
        start: index * size,
        end: (index + 1) * size,
      });
      // 将一个可读流（readStream）的数据传输到一个可写流（writeStream）中，实现数据的读取和写入操作
      readStream.pipe(writeStream);

      //监听写入完成删除分片
      readStream.on("end", async () => {
        let res = await fse.unlink(chunkPath);
        resolve(res);
      });
    });
  });
  // 全部写入后删除切片目录
  await Promise.all(list);
  fse.remove(chunkDir);

  res.status(200).json({
    ok: true,
    msg: "合并成功",
  });
});
app.post("/verify", async (req, res) => {
  const { fileName, fileHash } = req.body;
  console.log(fileHash);
  console.log(fileName);

  // 获取切片文件夹
  const chunkDir = path.resolve(UPLOAD_DIR, fileHash);
  let chunkPaths = [];
  //读取切片目录下的所有文件
  if (fse.existsSync(chunkDir)) {
    chunkPaths = await fse.readdir(chunkDir);
  }
  console.log(chunkPaths);

  // 完整的文件路径
  let filePath = path.resolve(UPLOAD_DIR, fileHash + extractExt(fileName));

  //存在不需要上传
  if (fse.existsSync(filePath)) {
    res.status(200).json({
      ok: true,
      data: {
        shouldUpload: false,
      },
    });
  } else {
    // 文件不在服务器中，就需要上传，并且返回服务器上已经存在的切片
    res.status(200).json({
      ok: true,
      data: {
        shouldUpload: true,
        uploadedList: chunkPaths,
      },
    });
  }
});
app.listen(3000, () => {
  console.log("http://localhost:3000");
});
